package net.softwarefabrik.bde.core.model.maven;

import java.io.File;

import net.softwarefabrik.bde.core.model.BDEConstants;
import net.softwarefabrik.bde.core.model.BDEException;
import net.softwarefabrik.bde.core.util.FileUtil;

/**
 * Manages the local Maven 2 repository. Can be used as is or subclassed to
 * support IDE specific behaviour (i.e. listeners, ...).
 * 
 * @author Matthias Kuespert
 */
public class RepositoryManager {

    /**
     * The locations to check when trying to download a file.
     */
    private String[] remoteLocations = new String[] {};

    /**
     * The root directory of the local Maven repository.
     * 
     */
    private File     localRoot       = null;

    private File download(ArtifactInfo artifact, String location) throws BDEException {
        String artifactMavenLocation = artifact.getMavenLocation();
        String artifactURL = location + artifactMavenLocation;
        if (FileUtil.checkUrl(artifactURL)) {
            String localPath = this.localRoot + artifactMavenLocation;
            FileUtil.downloadFile(artifactURL, localPath);
            File f = new File(localPath);
            return f.exists() ? f : null;
        }
        return null;
    }

    private File download(ArtifactInfo artifact) throws BDEException {
        if (getRemoteLocations().length == 0) {
            throw new BDEException("No remote Maven repositories specified.");
        }
        for (String location : getRemoteLocations()) {
            File file = download(artifact, location);
            if (null != file) {
                return file;
            }
        }
        String msg = "The file '"
                     + artifact.getMavenLocation()
                     + "' could not be found in any of the following remote Maven 2 repositories:\n";
        for (String location : this.remoteLocations) {
            msg += "   - " + location + BDEConstants.STD_LINE_SEPARATOR;
        }
        throw new BDEException(msg);
    }

    protected void setLocalRepositoryLocation(File directory) throws BDEException {
        if (null == directory) {
            throw new BDEException("Invalid parameter for Maven repository location: null");
        }
        if (!directory.exists()) {
            throw new BDEException("Non existing Maven repository location: "
                                   + directory.getAbsolutePath());
        }
        this.localRoot = directory;
    }

    /**
     * @param remoteLocations the remoteLocations to set
     */
    protected final void setRemoteLocations(String[] remoteLocations) {
        if (null == remoteLocations
            || (remoteLocations.length > 0 && remoteLocations[0].equals(BDEConstants.EMPTY_STRING))) {
            this.remoteLocations = new String[] {};
        } else {
            this.remoteLocations = remoteLocations;
        }
    }

    /**
     * Retrieves the given artifact from the local repository or - if
     * not found - from the remote ones.
     * 
     * @param artifact The artifact to load.
     * @param download If true and the file is already available in the local
     *        repository the file is downloaded again.
     * @return The artifact file if found in the local repository.
     * @throws BDEException if the artifact could not be retrieved
     */
    protected File get(ArtifactInfo artifact, boolean forceDownload) throws BDEException {
        File file = find(artifact);
        if (null == file || forceDownload) {
            return download(artifact);
        }
        return file;
    }

    public RepositoryManager(File directory, String[] remoteLocations) throws BDEException {
        if (null != directory) {
            setLocalRepositoryLocation(directory);
        }
        setRemoteLocations(remoteLocations);
    }

    public File find(ArtifactInfo artifact) throws BDEException {
        if (null == this.localRoot) {
            throw new BDEException("Error: no local repository set.");
        }
        String name = this.localRoot + artifact.getMavenLocation();
        File file = new File(name);
        return file.exists() ? file : null;
    }
    
    /**
     * Convenience method which does not force a download.
     * 
     * @param artifact The artifact to load.
     * @return The artifact file if found in the local repository
     * @throws BDEException if the artifact could not be retrieved
     */
    public final File get(ArtifactInfo artifact) throws BDEException {
        return get(artifact, false);
    }

    /**
     * Convenience method which does force a download.
     * 
     * @param artifact The artifact to load.
     * @return The artifact file if found in the local repository or null if the
     *         artifact could not be found.
     * @throws BDEException if the artifact could not be retrieved
     */
    public final File reget(ArtifactInfo artifact) throws BDEException {
        return get(artifact, true);
    }

    /**
     * @return the remoteLocations
     */
    public final String[] getRemoteLocations() {
        return this.remoteLocations;
    }
}
